package eerbaar.client.internal.exp;

import eerbaar.client.exp.ExpException;
import eerbaar.client.exp.ICmdFactory;
import eerbaar.client.exp.IEvaluator;
import eerbaar.client.exp.IExp;
import eerbaar.client.exp.INounFactory;
import eerbaar.client.exp.IOperatorFactory;
import eerbaar.client.exp.IScope;
import eerbaar.client.exp.Token;
import eerbaar.client.exp.TokenIterator;
import eerbaar.shared.tree.INode;

public class Learned implements IEvaluator {

    private IExp exp;

    private final ICmdFactory factory;

    private final INounFactory nounFactory;

    private final IOperatorFactory operatorFactory;

    private final INode root;

    private Token token;

    public Learned(INode root, ICmdFactory factory,
            IOperatorFactory operatorFactory, INounFactory nounFactory) {
        this.root = root;
        this.factory = factory;
        this.operatorFactory = operatorFactory;
        this.nounFactory = nounFactory;
    }

    @Override
    public Object calcDestination(IScope scope) {

        return this.exp.calcDestination(scope);
    }

    @Override
    public IScope interpret(IScope scope) throws ExpException {

        return this.exp.interpret(scope);
    }

    @Override
    public boolean isInteresting(String elementName) {

        return this.exp.isInteresting(elementName);
    }

    @Override
    public IExp parse(TokenIterator iterator) {

        this.token = iterator.next();
        String value = this.factory.getLearnedValue(this.token.toString());
        TokenIterator valueIterator = new ExpService().scan(value);

        Evaluator e = new Evaluator(this.root, this.factory,
                this.operatorFactory, this.nounFactory);
        this.exp = e.parse(valueIterator);

        return this.exp;
    }

    @Override
    public void populateValueArea(IScope scope) {

        this.exp.populateValueArea(scope);
    }

    @Override
    public String toString() {

        return "" + this.token + "(" + this.exp + ")";
    }

    @Override
    public void updateArea(IScope scope) {

        this.exp.updateArea(scope);
    }
}
